import Canvas2DBase from "./Canvas2DBase";
import { FigCircle, FigLine2D, FigPath2D, FigPoint2D, FigString2D, POINT_TYPE } from "./Canvas2DItem";

class Figure2D extends Canvas2DBase{
  // range 为数组，当数组长度为1时，轴刻度范围为0-range[0]
  // 数组长度为2时，刻度范围为range[0]-range[1]
  constructor(width, height, rangeX, rangeY){
    super(width, height);
    this.type = 'Figure2D';

    this.initFigure2D(rangeX, rangeY);
  }

  // 初始化属性值
  initFigure2D(rangeX, rangeY){
    this.addAttribute('precision', 2        , 'number', '精度');
    // 初始化X轴
    if(rangeX === undefined){
      this.addAttribute('xMin'  , 0         , 'number', '坐标轴-X');
      this.addAttribute('xMax'  , 8         , 'number', '坐标轴-X');
      this.addAttribute('xScale', 1         , 'number', '坐标轴-X');
    }
    else if(rangeX.length === 1){
      this.addAttribute('xMin'  , 0         , 'number', '坐标轴-X');
      this.addAttribute('xMax'  , rangeX[0] , 'number', '坐标轴-X');
      this.addAttribute('xScale', 1         , 'number', '坐标轴-X');
    }
    else if(rangeX.length === 2){
      this.addAttribute('xMin'  , rangeX[0] , 'number', '坐标轴-X');
      this.addAttribute('xMax'  , rangeX[1] , 'number', '坐标轴-X');
      this.addAttribute('xScale', 1         , 'number', '坐标轴-X');
    }
    else if(rangeX.length === 3){
      this.addAttribute('xMin'  , rangeX[0] , 'number', '坐标轴-X');
      this.addAttribute('xMax'  , rangeX[1] , 'number', '坐标轴-X');
      this.addAttribute('xScale', rangeX[2] , 'number', '坐标轴-X');
    }
    else{
      this.addAttribute('xMin'  , 0         , 'number', '坐标轴-X');
      this.addAttribute('xMax'  , 8         , 'number', '坐标轴-X');
      this.addAttribute('xScale', 1         , 'number', '坐标轴-X');
    }
    this.addAttribute('showXAxis'       , true      , 'boolean' , '坐标轴-X');
    this.addAttribute('showXAxisLabel'  , true      , 'boolean' , '坐标轴-X');
    this.addAttribute('showXScale'      , true      , 'boolean' , '坐标轴-X');
    this.addAttribute('xAxisOrigin'     , 0         , 'number'  , '坐标轴-X');
    this.addAttribute('xAxisLineWidth'  , 1         , 'number'  , '坐标轴-X');
    this.addAttribute('xAxisColor'      , '#FF0000' , 'color'   , '坐标轴-X');
    this.addAttribute('xAxisLabel'      , 'X'       , 'string'  , '坐标轴-X');
    this.addAttribute('xAxisArrowAngle' , 30        , 'number'  , '坐标轴-X');
    this.addAttribute('xAxisArrowLength', 10        , 'number'  , '坐标轴-X');
    this.addAttribute('xScaleColor'     , '#000000' , 'color'   , '坐标轴-X');
    this.addAttribute('xScaleLength'    , 8         , 'number'  , '坐标轴-X');

    // 初始化Y轴
    if(rangeY === undefined){
      this.addAttribute('yMin'  , 0         , 'number', '坐标轴-Y');
      this.addAttribute('yMax'  , 8         , 'number', '坐标轴-Y');
      this.addAttribute('yScale', 1         , 'number', '坐标轴-Y');
    }
    else if(rangeY.length === 1){
      this.addAttribute('yMin'  , 0         , 'number', '坐标轴-Y');
      this.addAttribute('yMax'  , rangeY[0] , 'number', '坐标轴-Y');
      this.addAttribute('yScale', 1         , 'number', '坐标轴-Y');
    }
    else if(rangeY.length === 2){
      this.addAttribute('yMin'  , rangeY[0] , 'number', '坐标轴-Y');
      this.addAttribute('yMax'  , rangeY[1] , 'number', '坐标轴-Y');
      this.addAttribute('yScale', 1         , 'number', '坐标轴-Y');
    }
    else if(rangeY.length === 3){
      this.addAttribute('yMin'  , rangeY[0] , 'number', '坐标轴-Y');
      this.addAttribute('yMax'  , rangeY[1] , 'number', '坐标轴-Y');
      this.addAttribute('yScale', rangeY[2] , 'number', '坐标轴-Y');
    }
    else{
      this.addAttribute('yMin'  , 0         , 'number', '坐标轴-Y');
      this.addAttribute('yMax'  , 8         , 'number', '坐标轴-Y');
      this.addAttribute('yScale', 1         , 'number', '坐标轴-Y');
    }
    this.addAttribute('showYAxis'       , true      , 'boolean' , '坐标轴-Y');
    this.addAttribute('showYAxisLabel'  , true      , 'boolean' , '坐标轴-Y');
    this.addAttribute('showYScale'      , true      , 'boolean' , '坐标轴-Y');
    this.addAttribute('yAxisOrigin'     , 0         , 'number'  , '坐标轴-Y');
    this.addAttribute('yAxisLineWidth'  , 1         , 'number'  , '坐标轴-Y');
    this.addAttribute('yAxisColor'      , '#00FF00' , 'color'   , '坐标轴-Y');
    this.addAttribute('yAxisLabel'      , 'Y'       , 'string'  , '坐标轴-Y');
    this.addAttribute('yAxisArrowAngle' , 30        , 'number'  , '坐标轴-Y');
    this.addAttribute('yAxisArrowLength', 10        , 'number'  , '坐标轴-Y');
    this.addAttribute('yScaleColor'     , '#000000' , 'color'   , '坐标轴-Y');
    this.addAttribute('yScaleLength'    , 8         , 'number'  , '坐标轴-Y');
  }

  // 更新坐标信息
  _updateCoordinate(){
    const paddingX = parseInt(this.paddingX);
    const paddingY = parseInt(this.paddingY);
    const width    = this.width  - paddingX * 2;
    const height   = this.height - paddingY * 2;

    const xMin    = parseFloat(this.xMin);
    const xMax    = parseFloat(this.xMax);

    const yMin    = parseFloat(this.yMin);
    const yMax    = parseFloat(this.yMax);

    const nx      = Math.abs(xMax - xMin) + 2;
    const ny      = Math.abs(yMax - yMin) + 2;

    const stepX   = width  / nx;
    const stepY   = height / ny;

    this.stepX    = stepX;
    this.stepY    = stepY;
  }
  // 绘制坐标轴
  drawAxes(){
    const paddingX = parseInt(this.paddingX);
    const paddingY = parseInt(this.paddingY);
    const width    = this.width  - paddingX * 2;
    const height   = this.height - paddingY * 2;

    this._updateCoordinate();
    const stepX   = this.stepX;
    const stepY   = this.stepY;

    const xMin    = parseFloat(this.xMin);
    const xMax    = parseFloat(this.xMax);
    const xScale  = parseFloat(this.xScale);

    const yMin    = parseFloat(this.yMin);
    const yMax    = parseFloat(this.yMax);
    const yScale  = parseFloat(this.yScale);

    // X
    if(this.showXAxis){
      const origin       = parseFloat(this.xAxisOrigin);
      const lineWidth    = parseFloat(this.xAxisLineWidth);
      const color        = this.xAxisColor;
      const arrowLength  = parseFloat(this.xAxisArrowLength);
      const arrowRadian  = parseFloat(this.xAxisArrowAngle) * Math.PI / 180;
      const arrowDx      = arrowLength * Math.cos(arrowRadian);
      const arrowDy      = arrowLength * Math.sin(arrowRadian);
      const label        = this.xAxisLabel;

      // 轴
      this._drawLine(
        paddingX, height + paddingY - stepY * (origin + 1), 
        paddingX + width, height + paddingY - stepY * (origin + 1), 
        lineWidth, this.lineStyle['solid'], color
      );
      // 箭头
      this._drawLine(
        paddingX + width, height + paddingY - stepY * (origin + 1),
        paddingX + width - arrowDx, height + paddingY - stepY * (origin + 1) + arrowDy, 
        lineWidth, this.lineStyle['solid'], color
      );
      this._drawLine(
        paddingX + width, height + paddingY - stepY * (origin + 1),
        paddingX + width - arrowDx, height + paddingY - stepY * (origin + 1) - arrowDy, 
        lineWidth, this.lineStyle['solid'], color
      );
      // 标签
      if(this.showXAxisLabel){
        this._drawString(
          label, 
          paddingX + width - arrowDx - this.getTextWidth(label), 
          height + paddingY - stepY * (origin + 1) + arrowDy + parseInt(this.fontSize), 
          color, this.font, this.fontSize, true, lineWidth, [], false );
      }
      // 刻度
      if(this.showXScale){
        const sColor = this.xScaleColor;
        const sLen   = parseInt(this.xScaleLength);
        var flagX = true;
        for(var x = xMin; x <= xMax; x += xScale){
          this._drawLine(
            paddingX + (x - xMin + 1) * stepX, height + paddingY - stepY * (origin + 1),
            paddingX + (x - xMin + 1) * stepX, height + paddingY - stepY * (origin + 1) - (flagX?sLen:sLen/2),
            lineWidth * 2, [], sColor
          );
          this._drawString(
            x.toFixed(this.precision - 1),
            paddingX + (x - xMin + 1) * stepX, 
            height + paddingY - stepY * (origin + 1) + parseInt(this.fontSize), 
            sColor, this.font, this.fontSize, true, lineWidth, [], false
          );
          flagX = !flagX;
        }
      }
    }
    // Y
    if(this.showYAxis){
      const origin       = parseFloat(this.yAxisOrigin);
      const lineWidth    = parseFloat(this.yAxisLineWidth);
      const color        = this.yAxisColor;
      const arrowLength  = parseFloat(this.yAxisArrowLength);
      const arrowRadian  = parseFloat(this.yAxisArrowAngle) * Math.PI / 180;
      const arrowDx      = arrowLength * Math.sin(arrowRadian);
      const arrowDy      = arrowLength * Math.cos(arrowRadian);
      const label        = this.yAxisLabel;
      // 轴
      this._drawLine(
        paddingX + stepX * (origin + 1), height + paddingY, 
        paddingX + stepX * (origin + 1), paddingY, 
        lineWidth, this.lineStyle['solid'], color
      );
      // 箭头
      this._drawLine(
        paddingX + stepX * (origin + 1), paddingY, 
        paddingX + stepX * (origin + 1) + arrowDx, paddingY + arrowDy, 
        lineWidth, this.lineStyle['solid'], color
      );
      this._drawLine(
        paddingX + stepX * (origin + 1), paddingY, 
        paddingX + stepX * (origin + 1) - arrowDx, paddingY + arrowDy, 
        lineWidth, this.lineStyle['solid'], color
      );
      // 标签
      if(this.showYAxisLabel){
        this._drawString(
          label, 
          paddingX + stepX * (origin + 1) - arrowDx - this.getTextWidth(label), 
          paddingY + arrowDy + parseInt(this.fontSize), 
          color, this.font, this.fontSize, true, lineWidth, [], false );
      }
      // 刻度
      if(this.showYScale){
        const sColor = this.yScaleColor;
        const sLen   = parseInt(this.yScaleLength);
        var flagY = true;
        for(var y = yMin; y <= yMax; y += yScale){
          this._drawLine(
            paddingX + stepX * (origin + 1), height - (y - yMin + 1) * stepY + paddingY,
            paddingX + stepX * (origin + 1) + (flagY?sLen:sLen/2), height - (y - yMin + 1) * stepY + paddingY, 
            lineWidth * 2, [], sColor
          );
          this._drawString(
            y.toFixed(this.precision - 1),
            paddingX + stepX * (origin + 1) - this.getTextWidth(x.toFixed(this.precision)), 
            height - (y - yMin + 1) * stepY + paddingY, 
            sColor, this.font, this.fontSize, true, lineWidth, [], false
          );
          flagY = !flagY;
        }
      }
    }
  }
  // 坐标转位置
  coordinateToPosition(cx, cy){
    const paddingX = parseInt(this.paddingX);
    const paddingY = parseInt(this.paddingY);
    const height   = this.height - paddingY * 2;

    const xMin    = parseFloat(this.xMin);
    const yMin    = parseFloat(this.yMin);

    this._updateCoordinate();

    const stepX   = this.stepX;
    const stepY   = this.stepY;

    const x = (parseFloat(cx) - xMin + 1) * stepX + paddingX;
    const y = height - (parseFloat(cy) - yMin + 1) * stepY + paddingY; 

    return [x, y];
  }
  // 位置转坐标
  positionToCoordinate(x, y){
    const paddingX = parseInt(this.paddingX);
    const paddingY = parseInt(this.paddingY);
    const height   = this.height - paddingY * 2;
    const xMin    = parseFloat(this.xMin);
    const yMin    = parseFloat(this.yMin);

    this._updateCoordinate();

    const stepX   = this.stepX;
    const stepY   = this.stepY;

    const precision = parseInt(this.precision);

    const cx      = ((x - paddingX) / stepX - 1 + xMin).toFixed(precision);
    const cy      = ((height - (y - paddingY)) / stepY - 1 + yMin).toFixed(precision);

    return [cx, cy];
  }

  // 在坐标位置画圆
  _drawCircleByCoordinate(cx, cy, r=5, fill=false, start=0, end=360, color='#000000', lineWidth=1, lineStyle=[]){
    const pos = this.coordinateToPosition(cx, cy);
    this._drawCircle(pos[0], pos[1], r, fill, start, end, color, lineWidth, lineStyle);
  }
  // 在坐标位置画线段
  _drawLineByCoordinate(cx1, cy1, cx2, cy2, lineWidth=1, lineStyle=[], color='#000000'){
    const pos1 = this.coordinateToPosition(cx1, cy1);
    const pos2 = this.coordinateToPosition(cx2, cy2);
    this._drawLine(pos1[0], pos1[1], pos2[0], pos2[1], lineWidth, lineStyle, color);
  }
  // 在坐标位置画矩形
  _drawRectangleByCoordinate(cx, cy, w, h, fill=false, color='#000000', lineWidth=1, lineStyle=[]){
    const pos = this.coordinateToPosition(cx, cy);
    w = w * this.stepX;
    h = h * this.stepY;
    this._drawRectangle(pos[0], pos[1], w, h, fill, color, lineWidth, lineStyle);
  }
  // 在坐标位置画字符串
  _drawStringByCoordinate(str, cx, cy, color='#000000', font=this.font, size=this.fontSize, fill=true, lineWidth=1, lineStyle=[]){
    const pos = this.coordinateToPosition(cx, cy);
    this._drawString(str, pos[0], pos[1], color, font, size, fill, lineWidth, lineStyle);
  }

  // 绘制游标显示坐标信息
  _drawCursor(x, y){
    this._drawLine(x, this.paddingY, x, this.height - this.paddingY);
    this._drawLine(this.paddingX, y, this.width - this.paddingX, y);
    const cooridinate = this.positionToCoordinate(x, y);
    this._drawString(`(${cooridinate[0]},${cooridinate[1]})`, x, y);
  }
  // 绘制点信息
  _drawPoint(x, y){
    this._drawCircle(x, y, 3, true);
    const cooridinate = this.positionToCoordinate(x, y);
    this._drawString(`(${cooridinate[0]},${cooridinate[1]})`, x, y);
  }
  // 绘制线段信息
  _drawLineInfo(x1, y1, x2, y2){
    const cooridinate1 = this.positionToCoordinate(x1, y1);
    const cooridinate2 = this.positionToCoordinate(x2, y2);
    const w = cooridinate2[0] - cooridinate1[0];
    const h = cooridinate2[1] - cooridinate1[1];
    const len = Math.sqrt(w*w + h*h).toFixed(2);
    this._drawStringByWindowPosition( `Line:${len}`, x2, y2);
  }
  // 绘制矩形信息
  _drawRectInfo(x1, y1, x2, y2){
    const cooridinate1 = this.positionToCoordinate(x1, y1);
    const cooridinate2 = this.positionToCoordinate(x2, y2);
    const w = Math.abs(cooridinate2[0] - cooridinate1[0]).toFixed(this.precision);
    const h = Math.abs(cooridinate2[1] - cooridinate1[1]).toFixed(this.precision);
    this._drawStringByWindowPosition( `Rect:[${w}x${h}]`, x1, y1);
  }

  // 添加圆到图
  addCircle(p1, p2, color='#000000', lineWidth=2, lineStyle=[]){
    const newCircle = new FigCircle(p1, p2, color, lineWidth, lineStyle);
    this.items.push(newCircle);
    return newCircle.uuid;
  }

  // 添加点到画图
  addPoint(cx, cy, size=3, style=0, color='#000000', lineWidth=2, lineStyle=[]){
    // const pos = this.coordinateToPosition(cx, cy);
    const newPoint = new FigPoint2D(cx, cy, size, style, color, lineWidth, lineStyle);
    this.items.push(newPoint);
    return newPoint.uuid;
  }
  // 添加线段
  addLine(p1, p2, lineWidth=2, lineStyle=[], color='#000000'){
    // const pos1 = this.coordinateToPosition(p1[0], p1[1]);
    // const pos2 = this.coordinateToPosition(p2[0], p2[1]);
    const newLine = new FigLine2D(p1[0], p1[1], p2[0], p2[1], lineWidth, lineStyle, color);
    this.items.push(newLine);
    return newLine.uuid;
  }
  // 添加路径
  addPath(points, lineWidth=2, lineStyle=[], fill=false, color='#000000'){
    // let positions = [];
    // for(var i=0, il=points.length; i < il; i++){
    //   const newPos = this.coordinateToPosition(points[i][0], points[i][1]);
    //   positions.push(newPos);
    // }
    const newPath = new FigPath2D(points, lineWidth, lineStyle, fill, color);
    this.items.push(newPath);
    return newPath.uuid;
  }
  // 添加字符串
  addString(str, cx, cy, fill=false, color='#000000'){
    // const pos = this.coordinateToPosition(cx, cy);
    const newString = new FigString2D(str, cx, cy, this.font, this.fontSize, fill, color);
    this.items.push(newString);
    return newString.uuid;
  }

  clearAll(){
    this.items = [];
    this.update();
  }

  update(){

    this.clear();
    this.resize();
    this.drawBorder();
    this.drawGrid();

    this.drawAxes();

    this.renderItems();
    this.updateHelper();
  }
}

function showPointsInFigure(fig, points, size=2, type=POINT_TYPE.Circle, color='#000000'){
  if(!fig) return;
  if(!points || !points.length) return;
  for(let i = 0, il = points.length; i < il; i++){
    const point = points[i];
    if(point.length === 2){
      fig.addPoint(point[0], point[1], size, type, color);
    }
  }
  fig.update();
}

export default Figure2D;
export {showPointsInFigure};